<?php

namespace app\api\middleware;

use app\common\exception\AdminException;
use think\facade\Db;
use think\facade\Event;
use think\Request;
use think\facade\Cache;

class RiskControl
{
    /**
     * 中间件入口：处理每个请求
     *
     * @param Request $request 当前请求对象
     * @param \Closure $next 下一个中间件或控制器
     * @return mixed
     */
    public function handle(Request $request, \Closure $next): mixed
    {
        // 1. 获取当前用户ID（假设登录后通过中间件注入）
        $userId = $this->getUserId($request);
        if (!$userId) {
            return $next($request); // 未登录用户不检测
        }

        // 2. 收集设备与网络上下文信息
        $context = $this->collectContext($request);

        // 3. 白名单检查（测试账号、本地IP等可跳过）
        if ($this->isWhitelisted($userId, $context['ip'])) {
            return $next($request);
        }

        // 4. 获取所有启用的风险标签配置（从数据库或缓存）
        $riskTags = $this->getRiskTags();

        // 5. 遍历所有标签，逐一检测是否触发
        $detectedTags = [];
        foreach ($riskTags as $tagCode => $config) {
            if ($this->checkRisk($tagCode, $userId, $context)) {
                $detectedTags[] = $tagCode;
            }
        }

        // 6. 对每个触发的标签：
        //    - 记录到 user_risk_tag 表（用户-标签关系）
        //    - 触发事件，由监听器处理后续动作
        foreach ($detectedTags as $tagCode) {
            $this->applyRiskTag($userId, $tagCode);
            Event::trigger('risk.tag.applied', $userId, $tagCode, $context);
        }

        // 7. 【高风险拦截】命中 high 级别标签直接拒绝访问
        $highRiskTags = ['emulator_user', 'proxy_user', 'high_ip_risk'];
        if (array_intersect($highRiskTags, $detectedTags)) {
            throw new AdminException('您的访问存在安全风险，已被系统限制', 403);
        }

        // 8. 继续执行后续逻辑
        return $next($request);
    }

    // ==================== 风险检测逻辑 ====================

    /**
     * 检测是否为模拟器（常见特征：generic, sdk, qemu）
     */
    protected function isEmulator($ctx): bool
    {
        $brand = strtolower($ctx['device_brand'] ?? '');
        $model = strtolower($ctx['device_model'] ?? '');
        $indicators = ['sdk', 'google', 'generic', 'android sdk', 'qemu', 'emulator'];
        foreach ($indicators as $i) {
            if (str_contains($brand, $i) || str_contains($model, $i)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检测是否使用代理/VPN（需接入IP库，此处为模拟）
     */
    protected function isProxyUser($ip): bool
    {
        $proxyIps = ['1.1.1.1', '8.8.8.8', '103.10.10.10'];
        return in_array($ip, $proxyIps);
    }

    /**
     * 检测高IP风险：同一IP注册≥3个账号
     */
    protected function isHighIpRisk($ip): bool
    {
        return Db::name('user')
                ->where('register_ip', $ip)
//                ->where('create_time', '>', time() - 86400) // 24小时内
                ->count() >= 3;
    }

    /**
     * 检测低价值用户：活跃但无转化（如下单、支付）
     */
    protected function isLowValueUser($userId): bool
    {
        $active = Db::name('user_behavior')->where('user_id', $userId)->count() > 10;
        $paid   = Db::name('orders')->where('user_id', $userId)->where('status', 'paid')->count();
        return $active && $paid == 0;
    }

    /**
     * 检测频繁提现：1小时内≥3次
     */
    protected function isFrequentWithdraw($userId): bool
    {
        $count = get_config('app.ip_max_users');
        return Db::name('withdrawal_apply')
                ->where('user_id', $userId)
                ->where('create_time', '>', time() - 3600)
                ->count() >= $count;
    }

    /**
     * 检测设备是否ROOT
     */
    protected function isRootedDevice($ctx): bool
    {
        return ($ctx['is_rooted'] ?? 0) == 1;
    }

    /**
     * 检测频繁登录：1小时内登录>5次（依赖缓存）
     */
    protected function isFrequentLogin($userId): bool
    {
        $count = Cache::get("login_count:{$userId}", 0);
        return $count > 5;
    }

    // ==================== 工具方法 ====================

    /**
     * 获取用户ID（示例：从请求对象中获取）
     */
    protected function getUserId($request)
    {
        return $request->userInfo['user_id'] ?? null;
    }

    /**
     * 收集请求上下文信息（用于风控分析）
     */
    protected function collectContext($request): array
    {
        return [
            'ip'              => $request->ip(),
            'app_version'     => $request->header('App-Version'),
            'device_platform' => $request->header('Device-Platform'),
            'device_type'     => $request->header('Device-Type'),
            'device_brand'    => $request->header('Device-Brand'),
            'device_model'    => $request->header('Device-Model'),
            'device_os'       => $request->header('Device-OS'),
            'latitude'        => $request->param('latitude'),
            'longitude'       => $request->param('longitude'),
            'carrier'         => $request->param('carrier'),
            'is_rooted'       => $request->param('is_rooted', 0),
        ];
    }

    /**
     * 白名单判断（测试账号、本地IP等）
     */
    protected function isWhitelisted($userId, $ip): bool
    {
        return in_array($userId, [1]) || $ip === '127.0.0.1';
    }

    /**
     * 记录用户风险标签（多对多关系）
     */
    protected function applyRiskTag($userId, $tagCode): void
    {
        $res = Db::name('risk_tag')->where('code', $tagCode)->find();
        Db::name('user_risk_tag')->insert([
            'user_id'  => $userId,
            'tag_code' => $tagCode,
            'tag_name' => $res['tag_name'],
            'tag_id'   => $res['id'],
            'create_time' => time()
        ]);
    }

    /**
     * 从数据库获取所有启用的风险标签（带缓存）
     */
    protected function getRiskTags()
    {
        return cache('risk_tags_config', function () {
            $tags = Db::name('risk_tag')
                ->where('status', 1)
                ->column('severity,score', 'code');
            return $tags ?: [];
        });
    }

    /**
     * 统一风险检测入口
     */
    protected function checkRisk($tagCode, $userId, $ctx): bool
    {
        return match ($tagCode) {
            'emulator_user' => $this->isEmulator($ctx),
            'proxy_user' => $this->isProxyUser($ctx['ip']),
            'high_ip_risk' => $this->isHighIpRisk($ctx['ip']),
//            'low_value_user' => $this->isLowValueUser($userId),
            'frequent_withdraw' => $this->isFrequentWithdraw($userId),
            'rooted_device' => $this->isRootedDevice($ctx),
            'frequent_login' => $this->isFrequentLogin($userId),
            default => false,
        };
    }
}